home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / Level 0 Macintosh 01Jan95 / Screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-27  |  47.8 KB  |  1,592 lines  |  [TEXT/KAHL]

  1. /* Screen.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #ifdef THINK_C
  25.     #pragma options(pack_enums)
  26. #endif
  27. #include <menus.h>
  28. #include <Quickdraw.h>
  29. #include <Windows.h>
  30. #include <Fonts.h>
  31. #include <TextEdit.h>
  32. #include <Dialogs.h>
  33. #include <Script.h>
  34. #include <GestaltEqu.h>
  35. #ifdef THINK_C
  36.     #pragma options(!pack_enums)
  37. #endif
  38.  
  39. #include "Screen.h"
  40. #include "Menus.h"
  41. #include "Memory.h"
  42. #include "EventLoop.h"
  43. #include "Scrap.h"
  44. #include "Array.h"
  45. #include "Files.h"
  46.  
  47.  
  48. /* maximum string length that can be sized in a single call to TextWidth or DrawText */
  49. /* (such a big number doesn't actually make much sense since 65535 is the number of */
  50. /* pixels, so if there are 32767 chars, we are way over the QuickDraw limit.) */
  51. #define MAXTEXTSIZING (32767)
  52.  
  53. #define MINWIDTH (20)
  54. #define MINHEIGHT (20)
  55.  
  56.  
  57. /* this structure contains everything about a window */
  58. struct WinType
  59.     {
  60.         /* document window or dialog box */
  61.         WinForm                                WhatKindOfWindow;
  62.         /* callback routine for redrawing it */
  63.         void                                    (*UpdateRoutine)(void* Refcon);
  64.         /* reference value for callback */
  65.         void*                                    Refcon;
  66.         /* current clip rect (for AddClipRect) */
  67.         Rect                                    CurrentClipRect;
  68.         /* actual window record */
  69.         WindowRecord                    ActualWindow;
  70.     };
  71.  
  72.  
  73. /* structure for bitmap */
  74. struct Bitmap
  75.     {
  76.         /* bytes per row for larger than image or partial bitmaps */
  77.         short                                    BytesPerRow; /* 2 bytes */
  78.         /* dimensions of bitmap */
  79.         OrdType                                Width; /* 2 bytes */
  80.         OrdType                                Height; /* 2 bytes */
  81.         /* the bitmap that the system uses */
  82.         BitMap                                SystemBitmap; /* 14 bytes */
  83.         /* data array here (block will actually be as large as necessary) */
  84.         unsigned char                    Data[1]; /* long word aligned (20th offset) */
  85.     };
  86.  
  87.  
  88. /* list of windows */
  89. static ArrayRec*                    OurWindowList;
  90.  
  91. /* list of windows that need to be updated */
  92. static ArrayRec*                    PendingDeferredUpdates;
  93.  
  94. /* debugging flag */
  95. EXECUTE(static MyBoolean    Initialized = False;)
  96.  
  97. /* pattern bitmap definitions.  patterns are 8x8 pixel blocks */
  98. static Pattern                        PatternMapping[5] =
  99.     {
  100.         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* White */
  101.         {0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22}, /* Light Grey */
  102.         {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}, /* Medium Grey */
  103.         {0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD}, /* Dark Grey */
  104.         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} /* Black */
  105.     };
  106.  
  107. /* since I don't know how to get a list of fonts, I make this menu */
  108. /* which contains all of the fonts and then I extract the names from it */
  109. static MenuHandle                    FunnyFontMenu;
  110.  
  111. /* this array contains all of the modal dialog boxes.  the most recent one is */
  112. /* at the end of the array */
  113. static ArrayRec*                    DialogBoxList; /* of WinType's */
  114.  
  115.  
  116. /* Initialize the screen management subsystem.  This routine must be called before */
  117. /* any graphics routines are called.  this routine initializes the entire Level 0 */
  118. /* module set except for some optional modules (like Network).  if it returns  */
  119. /* False then initialization failed and the program must terminate immediately. */
  120. MyBoolean                        InitializeScreen(void)
  121.     {
  122.         ERROR(Initialized,PRERR(ForceAbort,"InitializeScreen called more than once"));
  123.         /* initialize operating system managers */
  124.         InitGraf(&qd.thePort);
  125.         InitFonts();
  126.         InitWindows();
  127.         TEInit();
  128.         InitDialogs(0);
  129.         InitCursor();
  130.         InitMenus();
  131. #ifdef THINK_C
  132.     #if /*__option(mc68020) ||*/ __option(mc68881)
  133.         {
  134.             long                Result;
  135.  
  136.             if (noErr != Gestalt(gestaltFPUType,&Result))
  137.                 {
  138.                     return False;
  139.                 }
  140.             if (Result == gestaltNoFPU)
  141.                 {
  142.                     PRERR(ForceAbort,"This program requires a floating point coprocessor.");
  143.                     return False;
  144.                 }
  145.         }
  146.     #endif
  147.     #if __option(profile)
  148.         {
  149.             void                InitializeProfile(void);
  150.  
  151.             InitializeProfile();
  152.         }
  153.     #endif
  154. #endif
  155.         /* initialize our local memory manager */
  156.         if (!Eep_InitMemory())
  157.             {
  158.              FailurePoint1:
  159.                 return False;
  160.             }
  161.         /* initialize error handling.  no return code from this */
  162.         Eep_InitPRERR();
  163.         /* initialize our window array */
  164.         OurWindowList = NewArray();
  165.         if (OurWindowList == NIL)
  166.             {
  167.              FailurePoint2:
  168.                 Eep_FlushMemory();
  169.                 goto FailurePoint1;
  170.             }
  171.         /* initialize our deferred update list */
  172.         PendingDeferredUpdates = NewArray();
  173.         if (PendingDeferredUpdates == NIL)
  174.             {
  175.              FailurePoint3:
  176.                 DisposeArray(OurWindowList);
  177.                 goto FailurePoint2;
  178.             }
  179.         /* create dialog box array here */
  180.         DialogBoxList = NewArray();
  181.         if (DialogBoxList == NIL)
  182.             {
  183.              FailurePoint4:
  184.                 DisposeArray(PendingDeferredUpdates);
  185.                 goto FailurePoint3;
  186.             }
  187.         /* initialize cut and paste */
  188.         if (!Eep_InitializeScrapHandler())
  189.             {
  190.              FailurePoint5:
  191.                 DisposeArray(DialogBoxList);
  192.                 goto FailurePoint4;
  193.             }
  194.         /* initialize event loop */
  195.         if (!Eep_InitEventLoop())
  196.             {
  197.              FailurePoint6:
  198.                 Eep_ShutdownScrapHandler();
  199.                 goto FailurePoint5;
  200.             }
  201.         /* initialize menu subsystem */
  202.         if (!Eep_InitializeMenus())
  203.             {
  204.              FailurePoint7:
  205.                 Eep_ShutdownEventLoop();
  206.                 goto FailurePoint6;
  207.             }
  208.         /* initialize file system */
  209.         if (!Eep_InitializeFiles())
  210.             {
  211.              FailurePoint8:
  212.                 Eep_ShutdownMenus();
  213.                 goto FailurePoint7;
  214.             }
  215.         /* create the font menu for obtaining names of fonts */
  216.         /* menu manager uses menu IDs 256 and up, so we'll grab ID 1 */
  217.         FunnyFontMenu = NewMenu(1,"\pSilly Stupid Little Font Menu");
  218.         if (FunnyFontMenu == NIL)
  219.             {
  220.              FailurePoint9:
  221.                 Eep_ShutdownFiles();
  222.                 goto FailurePoint8;
  223.             }
  224.         AddResMenu(FunnyFontMenu,'FONT');
  225.         /* initialization done */
  226.         EXECUTE(Initialized = True;)
  227.         return True;
  228.     }
  229.  
  230.  
  231. /* close all open windows and perform any cleanup or server disconnection before */
  232. /* the program terminates */
  233. void                                ShutdownScreen(void)
  234.     {
  235.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  236.         /* shutdown subsystems in reverse order */
  237.         DisposeMenu(FunnyFontMenu); /* get rid of the funny font menu */
  238.         Eep_ShutdownFiles();
  239.         Eep_ShutdownMenus();
  240.         Eep_ShutdownEventLoop();
  241.         Eep_ShutdownScrapHandler();
  242.         /* clean up our own data structures */
  243.         ERROR(ArrayGetLength(OurWindowList) != 0,PRERR(AllowResume,
  244.             "ShutdownScreen:  there are still some windows open"));
  245.         DisposeArray(OurWindowList);
  246.         DisposeArray(PendingDeferredUpdates);
  247.         DisposeArray(DialogBoxList);
  248.         /* dump memory subsystem */
  249.         Eep_FlushMemory();
  250.         Eep_ShutdownPRERR();
  251.         EXECUTE(Initialized = False;)
  252. #ifdef THINK_C
  253.     #if __option(profile)
  254.         {
  255.             void                DumpProfile(void);
  256.             void                ProfileKillElement(unsigned char* FunctionName);
  257.  
  258.             ProfileKillElement("\pGetAnEvent");
  259.             ProfileKillElement("\pRelinquishCPUCheckCancel");
  260.             ProfileKillElement("\pPutFile");
  261.             ProfileKillElement("\pGetFileStandard");
  262.             ProfileKillElement("\pGetFileAny");
  263.             DumpProfile();
  264.         }
  265.     #endif
  266. #endif
  267.     }
  268.  
  269.  
  270. /* get size of screen.  If there are multiple screens, the result is implementation */
  271. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  272. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  273. /* least this much screen space in the form of a complete rectangle. */
  274. OrdType                            GetScreenHeight(void)
  275.     {
  276.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  277.         return qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - GetMBarHeight();
  278.     }
  279.  
  280.  
  281. /* get size of screen.  If there are multiple screens, the result is implementation */
  282. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  283. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  284. /* least this much screen space in the form of a complete rectangle. */
  285. OrdType                            GetScreenWidth(void)
  286.     {
  287.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  288.         return qd.screenBits.bounds.right - qd.screenBits.bounds.left;
  289.     }
  290.  
  291.  
  292. /* how big is a window's title bar */
  293. OrdType                            WindowTitleBarHeight(WinForm WindowKind)
  294.     {
  295.         switch (WindowKind)
  296.             {
  297.                 case eDocumentWindow:
  298.                     return 19;
  299.                 case eDialogWindow:
  300.                 case eModelessDialogWindow:
  301.                     return 6;
  302.                 default:
  303.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  304.             }
  305.     }
  306.  
  307.  
  308. /* how big are the other edges of a window */
  309. OrdType                            WindowOtherEdgeWidths(WinForm WindowKind)
  310.     {
  311.         switch (WindowKind)
  312.             {
  313.                 case eDocumentWindow:
  314.                     return 2;
  315.                 case eDialogWindow:
  316.                 case eModelessDialogWindow:
  317.                     return 6;
  318.                 default:
  319.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  320.             }
  321.     }
  322.  
  323.  
  324. /* create a new window.  if WindowKind = eDocumentWindow, then the window is a */
  325. /* standard window with a name (image is implementation defined).  In this case */
  326. /* Zoomable determines whether there will be a "Maximize" button, and Closable */
  327. /* determines whether there will be a "Close" button. */
  328. /* The window returned will be considered in the "disabled" state and any */
  329. /* objects installed in it should be disabled.  Eventually GetAnEvent will return */
  330. /* an active window change event disabling the window previously on top and */
  331. /* enabling this window.  if there are dialog boxes, then the window will be */
  332. /* created under the lowest dialog box */
  333. WinType*                        MakeNewWindow(WinForm WindowKind, WinCloseType Closable,
  334.                                             WinZoomType Zoomable, WinSizingType Resizing, OrdType Left,
  335.                                             OrdType Top, OrdType Width, OrdType Height,
  336.                                             void (*UpdateRoutine)(void* Refcon), void* Refcon)
  337.     {
  338.         WinType*                    Window;
  339.         Rect                            Where;
  340.         short                            WDef;
  341.  
  342.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  343.         ERROR(UpdateRoutine == NIL,PRERR(ForceAbort,
  344.             "MakeNewWindow:  can't have NIL update routine"));
  345.         /* allocate the window record */
  346.         Window = (WinType*)AllocPtrCanFail(sizeof(WinType),"WindowRecord");
  347.         if (Window == NIL)
  348.             {
  349.              FailurePoint1:
  350.                 return NIL;
  351.             }
  352.         /* add window to window list */
  353.         if (!ArrayAppendElement(OurWindowList,Window))
  354.             {
  355.              FailurePoint2:
  356.                 ReleasePtr((char*)Window);
  357.                 goto FailurePoint1;
  358.             }
  359.         /* create the actual window */
  360.         if (Width < MINWIDTH)
  361.             {
  362.                 Width = MINWIDTH;
  363.             }
  364.         if (Height < MINHEIGHT)
  365.             {
  366.                 Height = MINHEIGHT;
  367.             }
  368.         Where.left = Left;
  369.         Where.top = Top + GetMBarHeight();
  370.         Where.right = Left + Width;
  371.         Where.bottom = Top + Height + GetMBarHeight();
  372.         switch (WindowKind)
  373.             {
  374.                 case eDocumentWindow:
  375.                     if (Zoomable == eWindowZoomable)
  376.                         {
  377.                             WDef = zoomNoGrow;
  378.                         }
  379.                      else
  380.                         {
  381.                             WDef = noGrowDocProc;
  382.                         }
  383.                     break;
  384.                 case eDialogWindow:
  385.                     WDef = dBoxProc;
  386.                     break;
  387.                 case eModelessDialogWindow:
  388.                     WDef = movableDBoxProc;
  389.                     break;
  390.                 default:
  391.                     EXECUTE(PRERR(ForceAbort,"MakeNewWindow:  unknown WindowKind"));
  392.                     break;
  393.             }
  394.         if (NIL == NewWindow(&(Window->ActualWindow),&Where,"\p"/*notitle*/,
  395.             True/*visible*/,WDef,
  396.             (
  397.                 /* is the window a document window when there are dialog windows? */
  398.                 ((ArrayGetLength(DialogBoxList) != 0)
  399.                 && (WindowKind != eDialogWindow)
  400.                 && (WindowKind != eModelessDialogWindow))
  401.             ?
  402.                 /* yes -- create under lowest dialog */
  403.                 (GrafPort*)&(((WinType*)ArrayGetElement(DialogBoxList,0))->ActualWindow)
  404.             :
  405.                 /* no -- create on top */
  406.                 (GrafPort*)-1L/*windowinfront*/
  407.             ),(Closable == eWindowClosable),(long)Window/*refcon is window's base pointer*/))
  408.             {
  409.              FailurePoint3:
  410.                 ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  411.                 goto FailurePoint2;
  412.             }
  413.         /* initialize static fields */
  414.         Window->CurrentClipRect.left = 0;
  415.         Window->CurrentClipRect.top = 0;
  416.         Window->CurrentClipRect.right = Width;
  417.         Window->CurrentClipRect.bottom = Height;
  418.         Window->UpdateRoutine = UpdateRoutine;
  419.         Window->Refcon = Refcon;
  420.         Window->WhatKindOfWindow = WindowKind;
  421.         /* if it's a dialog box, then add it to the list */
  422.         if ((WindowKind == eDialogWindow) || (WindowKind == eModelessDialogWindow))
  423.             {
  424.                 if (!ArrayAppendElement(DialogBoxList,Window))
  425.                     {
  426.                         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  427.                         goto FailurePoint3;
  428.                     }
  429.             }
  430.         return Window;
  431.     }
  432.  
  433.  
  434. /* change the size of the window.  The window will be guarranteed to be the specified */
  435. /* size, but significant portions may not be on screen, so be careful */
  436. void                                ResizeWindow(WinType* Window, OrdType Width, OrdType Height)
  437.     {
  438.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  439.         CheckPtrExistence(Window);
  440.         /* change window size */
  441.         SizeWindow((WindowPtr)&(Window->ActualWindow),Width,Height,False);
  442.         /* invalidate the window so it gets updated */
  443.         SetPort((WindowPtr)&(Window->ActualWindow));
  444.         InvalRect(&(Window->ActualWindow.port.portRect));
  445.     }
  446.  
  447.  
  448. /* close a window and release all associated space.  The window refnum may be reused */
  449. /* An active window change event will be issued activating the window that is */
  450. /* next in the stack.  If there are dialog boxes open, then the most recently */
  451. /* created one must be disposed or it is an error. */
  452. void                                KillWindow(WinType* Window)
  453.     {
  454.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  455.         CheckPtrExistence(Window);
  456.         ERROR((ArrayGetLength(DialogBoxList) != 0) && (ArrayFindElement(DialogBoxList,
  457.             Window) != ArrayGetLength(DialogBoxList) - 1),PRERR(ForceAbort,
  458.             "KillWindow:  dialog boxes exist and window isn't the topmost dialog box."));
  459.         Eep_WindowDying(Window);
  460.         ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  461.         if (ArrayGetLength(DialogBoxList) != 0)
  462.             {
  463.                 ERROR(ArrayFindElement(DialogBoxList,Window) == -1,PRERR(ForceAbort,
  464.                     "KillWindow:  couldn't find dialog box in the list"));
  465.                 ArrayDeleteElement(DialogBoxList,ArrayFindElement(DialogBoxList,Window));
  466.             }
  467.         /* remove it from the pending updates list if it's still there */
  468.         if (ArrayFindElement(PendingDeferredUpdates,Window) >= 0)
  469.             {
  470.                 ArrayDeleteElement(PendingDeferredUpdates,
  471.                     ArrayFindElement(PendingDeferredUpdates,Window));
  472.             }
  473.         /* dispose the OS window */
  474.         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  475.         /* dispose the window object */
  476.         ReleasePtr((char*)Window);
  477.     }
  478.  
  479.  
  480. /* get the size of the usable portion of the window */
  481. OrdType                            GetWindowHeight(WinType* Window)
  482.     {
  483.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  484.         CheckPtrExistence(Window);
  485.         return Window->ActualWindow.port.portRect.bottom
  486.             - Window->ActualWindow.port.portRect.top;
  487.     }
  488.  
  489.  
  490. /* get the size of the usable portion of the window */
  491. OrdType                            GetWindowWidth(WinType* Window)
  492.     {
  493.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  494.         CheckPtrExistence(Window);
  495.         return Window->ActualWindow.port.portRect.right
  496.             - Window->ActualWindow.port.portRect.left;
  497.     }
  498.  
  499.  
  500. /* Get the global coordinate location of the window */
  501. OrdType                            GetWindowXStart(WinType* Window)
  502.     {
  503.         Point                            Delta = {0,0};
  504.  
  505.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  506.         CheckPtrExistence(Window);
  507.         /* this is really goofy, but I can't think of any other way of doing it. */
  508.         SetPort((WindowPtr)&(Window->ActualWindow));
  509.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  510.         return Delta.h;
  511.     }
  512.  
  513.  
  514. /* Get the global coordinate location of the window */
  515. OrdType                            GetWindowYStart(WinType* Window)
  516.     {
  517.         Point            Delta = {0,0};
  518.  
  519.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  520.         CheckPtrExistence(Window);
  521.         SetPort((WindowPtr)&(Window->ActualWindow));
  522.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  523.         return Delta.v - GetMBarHeight();
  524.     }
  525.  
  526.  
  527. /* Adjust the global position of the window. */
  528. void                                SetWindowPosition(WinType* Window, OrdType NewXLocation,
  529.                                             OrdType NewYLocation)
  530.     {
  531.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  532.         CheckPtrExistence(Window);
  533.         MoveWindow((WindowPtr)&(Window->ActualWindow),NewXLocation,
  534.             NewYLocation + GetMBarHeight(),False);
  535.     }
  536.  
  537.  
  538. /* Get what type of window it is */
  539. WinForm                            GetWindowKind(WinType* Window)
  540.     {
  541.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  542.         CheckPtrExistence(Window);
  543.         return Window->WhatKindOfWindow;
  544.     }
  545.  
  546.  
  547. /* allow system to resize window after user clicked in some area */
  548. void                                UserGrowWindow(WinType* Window, OrdType X, OrdType Y)
  549.     {
  550.         Rect                            Limits = {64,64,32767,32767};
  551.         Point                            Where;
  552.         unsigned long            NewSize;
  553.  
  554.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  555.         CheckPtrExistence(Window);
  556.         SetPort((WindowPtr)&(Window->ActualWindow));
  557.         Where.h = X;
  558.         Where.v = Y;
  559.         LocalToGlobal(&Where);
  560.         NewSize = GrowWindow((WindowPtr)&(Window->ActualWindow),Where,&Limits);
  561.         SizeWindow((WindowPtr)&(Window->ActualWindow),
  562.             NewSize & 0xffff,(NewSize >> 16) & 0xffff,False);
  563.         Limits.left = 0;
  564.         Limits.top = 0;
  565.         Limits.right = GetWindowWidth(Window);
  566.         Limits.bottom = GetWindowHeight(Window);
  567.         /* invalidate window so it gets redrawn */
  568.         EraseRect(&Limits);
  569.         InvalRect(&Limits);
  570.     }
  571.  
  572.  
  573. /* bring window to the top of the window stack.  this will be silently ignored */
  574. /* if there are dialog boxes open. */
  575. void                                ActivateThisWindow(WinType* Window)
  576.     {
  577.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  578.         CheckPtrExistence(Window);
  579.         if (ArrayGetLength(DialogBoxList) == 0)
  580.             {
  581.                 /* only do it if there aren't any dialog boxes */
  582.                 SelectWindow((WindowPtr)&(Window->ActualWindow));
  583.             }
  584.     }
  585.  
  586.  
  587. /* this function is used by MakeWindowFitOnScreen */
  588. static MyBoolean        SeeIfWindowFitsOnScreen(OrdType X, OrdType Y,
  589.                                             OrdType Width, OrdType Height)
  590.     {
  591.         RgnHandle                    OurRegion;
  592.         RgnHandle                    Intersection;
  593.         MyBoolean                    Result;
  594.  
  595.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  596.  
  597.         /* default value:  in case we run out of memory, don't do anything */
  598.         Result = True;
  599.         /* we add some constants in here to account for window title bar */
  600.         Y = Y + GetMBarHeight() - 19;
  601.         Height = Height + 19;
  602.  
  603.         /* create a region for the window the user wants to create */
  604.         OurRegion = NewRgn();
  605.         if (OurRegion != NIL)
  606.             {
  607.                 SetRectRgn(OurRegion,X,Y,X + Width,Y + Height);
  608.  
  609.                 /* create a region to get the intersection of the window & the screen */
  610.                 Intersection = NewRgn();
  611.                 if (Intersection != NIL)
  612.                     {
  613.                         /* find the intersection of the regions */
  614.                         SectRgn(GetGrayRgn(),OurRegion,Intersection);
  615.  
  616.                         /* if the window region and the intersection are equal, then the window */
  617.                         /* fits on the screen */
  618.                         Result = EqualRgn(Intersection,OurRegion);
  619.  
  620.                         DisposeRgn(Intersection);
  621.                     }
  622.  
  623.                 DisposeRgn(OurRegion);
  624.             }
  625.  
  626.         return Result;
  627.     }
  628.  
  629.  
  630. /* this routine helps make sure the rectangle fits on the screen.  If the rectangle */
  631. /* already fits on the screen, X and Y will not be adjusted, but if it doesn't, some */
  632. /* undefined adjustment will be made to ensure that the rectangle fits on the screen. */
  633. /* If the rectangle is so large that it can't be made to fit on the screen, then */
  634. /* the size of the window is reduced so that the window will fit on screen. */
  635. void                                MakeWindowFitOnScreen(OrdType* X, OrdType* Y,
  636.                                             OrdType* Width, OrdType* Height)
  637.     {
  638.         RgnHandle                    OurRegion;
  639.         RgnHandle                    Intersection;
  640.  
  641.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  642.         ERROR((X == NIL) || (Y == NIL) || (Width == NIL) || (Height == NIL),PRERR(ForceAbort,
  643.             "MakeWindowFitOnScreen:  an output parameter is NIL"));
  644.         if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  645.             {
  646.                 *X = 3;
  647.                 *Y = 23;
  648.                 if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  649.                     {
  650.                         if (*Width > GetScreenWidth() - *X - 2 - 1)
  651.                             {
  652.                                 *Width = GetScreenWidth() - *X - 2 - 1;
  653.                             }
  654.                         if (*Height > GetScreenHeight() - *Y - 2 - 1)
  655.                             {
  656.                                 *Height = GetScreenHeight() - *Y - 2 - 1;
  657.                             }
  658.                     }
  659.             }
  660.     }
  661.  
  662.  
  663. /* obtain the edge of a window, conforming to the user interface */
  664. /* guidelines of the implementation's platform */
  665. OrdType                            AlertLeftEdge(OrdType AlertWidth)
  666.     {
  667.         short                            Temp;
  668.  
  669.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  670.         Temp = (GetScreenWidth() - AlertWidth) / 2;
  671.         if (Temp < 4)
  672.             {
  673.                 Temp = 4;
  674.             }
  675.         return Temp;
  676.     }
  677.  
  678.  
  679. /* obtain the edge of a window, conforming to the user interface */
  680. /* guidelines of the implementation's platform */
  681. OrdType                            AlertTopEdge(OrdType AlertHeight)
  682.     {
  683.         short                            Temp;
  684.  
  685.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  686.         Temp = (GetScreenHeight() / 3) - AlertHeight;
  687.         if (Temp < 4 + 20 + GetMBarHeight())
  688.             {
  689.                 Temp = 4 + 20 + GetMBarHeight();
  690.             }
  691.         return Temp;
  692.     }
  693.  
  694.  
  695. /* obtain the edge of a window, conforming to the user interface */
  696. /* guidelines of the implementation's platform */
  697. OrdType                            DialogLeftEdge(OrdType DialogWidth)
  698.     {
  699.         short                            Temp;
  700.  
  701.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  702.         Temp = (GetScreenWidth() - DialogWidth) / 2;
  703.         if (Temp < 4)
  704.             {
  705.                 Temp = 4;
  706.             }
  707.         return Temp;
  708.     }
  709.  
  710.  
  711. /* obtain the edge of a window, conforming to the user interface */
  712. /* guidelines of the implementation's platform */
  713. OrdType                            DialogTopEdge(OrdType DialogHeight)
  714.     {
  715.         short                Temp;
  716.  
  717.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  718.         Temp = (GetScreenHeight() - DialogHeight) / 3;
  719.         if (Temp < 4 + 20 + GetMBarHeight())
  720.             {
  721.                 Temp = 4 + 20 + GetMBarHeight();
  722.             }
  723.         return Temp;
  724.     }
  725.  
  726.  
  727. /* change window's name.  name should be a null-terminated string.  the only windows */
  728. /* guarranteed to have a title bar are eDocumentWindow's. */
  729. void                                SetWindowName(WinType* Window, char* Name)
  730.     {
  731.         unsigned char            NameTemp[256];
  732.         long                            Scan;
  733.  
  734.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  735.         CheckPtrExistence(Window);
  736.         ERROR(Name == NIL,PRERR(ForceAbort,"SetWindowName:  name is NIL"));
  737.         Scan = 0;
  738.         while ((Scan < 255) && (Name[Scan] != 0))
  739.             {
  740.                 NameTemp[Scan + 1] = Name[Scan];
  741.                 Scan += 1;
  742.             }
  743.         NameTemp[0] = Scan;
  744.         SetWTitle((WindowPtr)&(Window->ActualWindow),NameTemp);
  745.     }
  746.  
  747.  
  748. /* invoke a window's update routine */
  749. void                                CallWindowUpdate(WinType* Window)
  750.     {
  751.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  752.         CheckPtrExistence(Window);
  753.         (*Window->UpdateRoutine)(Window->Refcon);
  754.     }
  755.  
  756.  
  757. /* if the program is doing something so that processing an update event would */
  758. /* cause it to crash, then the window is marked and will be redrawn as soon as */
  759. /* possible.   This is used during RelinquishCPU in the EventLoop module since */
  760. /* the windowing system might be in an inconsistent state when that routine is */
  761. /* called.  (If we ignored the event, then the window would not be redrawn at all) */
  762. void                                MarkForDeferredUpdate(WinType* Window)
  763.     {
  764.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  765.         CheckPtrExistence(Window);
  766.         if (ArrayFindElement(PendingDeferredUpdates,Window) < 0)
  767.             {
  768.                 /* don't add it to list unless it isn't there */
  769.                 /* if this fails, then it'll just not redraw the window. */
  770.                 ArrayAppendElement(PendingDeferredUpdates,Window);
  771.             }
  772.     }
  773.  
  774.  
  775. /* redraw all windows whose updates have been deferred */
  776. void                                PerformDeferredUpdates(void)
  777.     {
  778.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  779.         while (ArrayGetLength(PendingDeferredUpdates) != 0)
  780.             {
  781.                 WinType*                    Window;
  782.  
  783.                 /* get the window */
  784.                 Window = (WinType*)ArrayGetElement(PendingDeferredUpdates,0);
  785.                 CheckPtrExistence(Window);
  786.                 /* remove the window from the deferred update list */
  787.                 ArrayDeleteElement(PendingDeferredUpdates,0);
  788.                 /* erase window */
  789.                 SetClipRect(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  790.                 DrawBoxErase(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  791.                 /* call the redraw callback */
  792.                 CallWindowUpdate(Window);
  793.             }
  794.     }
  795.  
  796.  
  797. /* get the refcon from the window */
  798. void*                                GetWindowRefcon(WinType* Window)
  799.     {
  800.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  801.         CheckPtrExistence(Window);
  802.         return Window->Refcon;
  803.     }
  804.  
  805.  
  806. /* set the clipping rectangle for the window.  Drawing outside of this rectangle */
  807. /* will not be change any of the window */
  808. void                                SetClipRect(WinType* Window, OrdType Left, OrdType Top,
  809.                                             OrdType Width, OrdType Height)
  810.     {
  811.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  812.         CheckPtrExistence(Window);
  813.         SetPort((WindowPtr)&(Window->ActualWindow));
  814.         Window->CurrentClipRect.left = Left;
  815.         Window->CurrentClipRect.top = Top;
  816.         Window->CurrentClipRect.right = Left + Width;
  817.         Window->CurrentClipRect.bottom = Top + Height;
  818.         ClipRect(&(Window->CurrentClipRect));
  819.     }
  820.  
  821.  
  822. /* constrain the clipping rectangle for the window.  The new clipping rectangle is */
  823. /* the intersection of the specified one and the previous one. */
  824. void                                AddClipRect(WinType* Window, OrdType Left, OrdType Top,
  825.                                             OrdType Width, OrdType Height)
  826.     {
  827.         Rect                            Old;
  828.  
  829.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  830.         CheckPtrExistence(Window);
  831.         SetPort((WindowPtr)&(Window->ActualWindow));
  832.         Old = Window->CurrentClipRect;
  833.         Window->CurrentClipRect.left = Left;
  834.         Window->CurrentClipRect.top = Top;
  835.         Window->CurrentClipRect.right = Left + Width;
  836.         Window->CurrentClipRect.bottom = Top + Height;
  837.         SectRect(&(Window->CurrentClipRect),&Old,&(Window->CurrentClipRect));
  838.         ClipRect(&(Window->CurrentClipRect));
  839.     }
  840.  
  841.  
  842. /* returns True if any part of the specified rectangle in the window is visible. */
  843. /* this is used for making redrawing more efficient. */
  844. MyBoolean                        IsRectVisible(WinType* Window, OrdType Left, OrdType Top,
  845.                                             OrdType Width, OrdType Height)
  846.     {
  847.         Rect                            Location;
  848.  
  849.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  850.         CheckPtrExistence(Window);
  851.         Location.left = Left;
  852.         Location.top = Top;
  853.         Location.right = Left + Width;
  854.         Location.bottom = Top + Height;
  855.         return (MyBoolean)RectInRgn(&Location,Window->ActualWindow.port.visRgn);
  856.     }
  857.  
  858.  
  859. /* Draw a line one pixel thick.  XDisp and YDisp may be negative. */
  860. void                                DrawLine(WinType* Window, Patterns Pattern,
  861.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  862.     {
  863.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  864.         CheckPtrExistence(Window);
  865.         SetPort((WindowPtr)&(Window->ActualWindow));
  866.         PenPat(&(PatternMapping[Pattern - eWhite]));
  867.         PenMode(srcCopy);
  868.         MoveTo(X,Y);
  869.         LineTo(X + XDisp,Y + YDisp);
  870.     }
  871.  
  872.  
  873. /* Draw a box with a 1 pixel thick frame.  Note that the last pixel touched */
  874. /* is X + XDisp - 1 and Y + YDisp - 1. */
  875. void                                DrawBoxFrame(WinType* Window, Patterns Pattern,
  876.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  877.     {
  878.         Rect                            Temp;
  879.  
  880.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  881.         CheckPtrExistence(Window);
  882.         SetPort((WindowPtr)&(Window->ActualWindow));
  883.         PenPat(&(PatternMapping[Pattern - eWhite]));
  884.         PenMode(srcCopy);
  885.         Temp.left = X;
  886.         Temp.top = Y;
  887.         Temp.right = X + XDisp;
  888.         Temp.bottom = Y + YDisp;
  889.         FrameRect(&Temp);
  890.     }
  891.  
  892.  
  893. /* paint the box with the specified pattern */
  894. void                                DrawBoxPaint(WinType* Window, Patterns Pattern,
  895.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  896.     {
  897.         Rect                            Temp;
  898.  
  899.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  900.         CheckPtrExistence(Window);
  901.         SetPort((WindowPtr)&(Window->ActualWindow));
  902.         PenPat(&(PatternMapping[Pattern - eWhite]));
  903.         PenMode(srcCopy);
  904.         Temp.left = X;
  905.         Temp.top = Y;
  906.         Temp.right = X + XDisp;
  907.         Temp.bottom = Y + YDisp;
  908.         PaintRect(&Temp);
  909.     }
  910.  
  911.  
  912. /* paint the box with white */
  913. void                                DrawBoxErase(WinType* Window, OrdType X, OrdType Y,
  914.                                             OrdType XDisp, OrdType YDisp)
  915.     {
  916.         Rect                            Temp;
  917.  
  918.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  919.         CheckPtrExistence(Window);
  920.         SetPort((WindowPtr)&(Window->ActualWindow));
  921.         Temp.left = X;
  922.         Temp.top = Y;
  923.         Temp.right = X + XDisp;
  924.         Temp.bottom = Y + YDisp;
  925.         EraseRect(&Temp);
  926.     }
  927.  
  928.  
  929. #if 0
  930. /* And-mask the contents of the box with the pattern */
  931. void                                DrawBoxScreen(WinType* Window, Patterns Pattern,
  932.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp);
  933.     {
  934.         Rect                            Temp;
  935.  
  936.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  937.         CheckPtrExistence(Window);
  938.         SetPort((WindowPtr)&(Window->ActualWindow));
  939.         PenPat(&(PatternMapping[Pattern - eWhite]));
  940.         PenMode(srcBic);
  941.         Temp.left = X;
  942.         Temp.top = Y;
  943.         Temp.right = X + XDisp;
  944.         Temp.bottom = Y + YDisp;
  945.         PaintRect(&Temp);
  946.     }
  947. #endif
  948.  
  949.  
  950. /* Draw a box, but round off the corners with circles. */
  951. void                                DrawRoundBoxFrame(WinType* Window, Patterns Pattern,
  952.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  953.                                             OrdType DiameterX, OrdType DiameterY)
  954.     {
  955.         Rect                            Temp;
  956.  
  957.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  958.         CheckPtrExistence(Window);
  959.         SetPort((WindowPtr)&(Window->ActualWindow));
  960.         PenPat(&(PatternMapping[Pattern - eWhite]));
  961.         PenMode(srcCopy);
  962.         Temp.left = X;
  963.         Temp.top = Y;
  964.         Temp.right = X + XDisp;
  965.         Temp.bottom = Y + YDisp;
  966.         FrameRoundRect(&Temp,DiameterX,DiameterY);
  967.     }
  968.  
  969.  
  970. /* Draw a box, but round off the corners with circles. */
  971. void                                DrawRoundBoxPaint(WinType* Window, Patterns Pattern,
  972.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  973.                                             OrdType DiameterX, OrdType DiameterY)
  974.     {
  975.         Rect                            Temp;
  976.  
  977.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  978.         CheckPtrExistence(Window);
  979.         SetPort((WindowPtr)&(Window->ActualWindow));
  980.         PenPat(&(PatternMapping[Pattern - eWhite]));
  981.         PenMode(srcCopy);
  982.         Temp.left = X;
  983.         Temp.top = Y;
  984.         Temp.right = X + XDisp;
  985.         Temp.bottom = Y + YDisp;
  986.         PaintRoundRect(&Temp,DiameterX,DiameterY);
  987.     }
  988.  
  989.  
  990. /* Draw a box, but round off the corners with circles. */
  991. void                                DrawRoundBoxErase(WinType* Window, OrdType X, OrdType Y,
  992.                                             OrdType XDisp, OrdType YDisp, OrdType DiameterX, OrdType DiameterY)
  993.     {
  994.         Rect                            Temp;
  995.  
  996.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  997.         CheckPtrExistence(Window);
  998.         SetPort((WindowPtr)&(Window->ActualWindow));
  999.         Temp.left = X;
  1000.         Temp.top = Y;
  1001.         Temp.right = X + XDisp;
  1002.         Temp.bottom = Y + YDisp;
  1003.         EraseRoundRect(&Temp,DiameterX,DiameterY);
  1004.     }
  1005.  
  1006.  
  1007. void                                DrawCircleFrame(WinType* Window, Patterns Pattern,
  1008.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  1009.     {
  1010.         Rect                            Temp;
  1011.  
  1012.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1013.         CheckPtrExistence(Window);
  1014.         SetPort((WindowPtr)&(Window->ActualWindow));
  1015.         PenPat(&(PatternMapping[Pattern - eWhite]));
  1016.         PenMode(srcCopy);
  1017.         Temp.left = X;
  1018.         Temp.top = Y;
  1019.         Temp.right = X + XDisp;
  1020.         Temp.bottom = Y + YDisp;
  1021.         FrameOval(&Temp);
  1022.     }
  1023.  
  1024.  
  1025. void                                DrawCirclePaint(WinType* Window, Patterns Pattern,
  1026.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  1027.     {
  1028.         Rect                            Temp;
  1029.  
  1030.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1031.         CheckPtrExistence(Window);
  1032.         SetPort((WindowPtr)&(Window->ActualWindow));
  1033.         PenPat(&(PatternMapping[Pattern - eWhite]));
  1034.         PenMode(srcCopy);
  1035.         Temp.left = X;
  1036.         Temp.top = Y;
  1037.         Temp.right = X + XDisp;
  1038.         Temp.bottom = Y + YDisp;
  1039.         PaintOval(&Temp);
  1040.     }
  1041.  
  1042.  
  1043. void                                DrawCircleErase(WinType* Window, OrdType X, OrdType Y,
  1044.                                             OrdType XDisp, OrdType YDisp)
  1045.     {
  1046.         Rect            Temp;
  1047.  
  1048.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1049.         CheckPtrExistence(Window);
  1050.         SetPort((WindowPtr)&(Window->ActualWindow));
  1051.         Temp.left = X;
  1052.         Temp.top = Y;
  1053.         Temp.right = X + XDisp;
  1054.         Temp.bottom = Y + YDisp;
  1055.         EraseOval(&Temp);
  1056.     }
  1057.  
  1058.  
  1059. /* fill a triangle */
  1060. void                                DrawTrianglePaint(WinType* Window, Patterns Pattern, OrdType X1,
  1061.                                             OrdType Y1, OrdType X2, OrdType Y2, OrdType X3, OrdType Y3)
  1062.     {
  1063.         PolyHandle                Poly;
  1064.  
  1065.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1066.         CheckPtrExistence(Window);
  1067.         SetPort((WindowPtr)&(Window->ActualWindow));
  1068.         Poly = OpenPoly();
  1069.         MoveTo(X1,Y1);
  1070.         LineTo(X2,Y2);
  1071.         LineTo(X3,Y3);
  1072.         LineTo(X1,Y1);
  1073.         ClosePoly();
  1074.         PenPat(&(PatternMapping[Pattern - eWhite]));
  1075.         PenMode(srcCopy);
  1076.         PaintPoly(Poly);
  1077.         KillPoly(Poly);
  1078.     }
  1079.  
  1080.  
  1081. /* Get the ID of a heavier screen font (Macintosh == Chicago) */
  1082. FontType                        GetUglyFont(void)
  1083.     {
  1084.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1085.         return systemFont;
  1086.     }
  1087.  
  1088.  
  1089. /* Get the ID of the default screen font (Macintosh == Geneva) */
  1090. FontType                        GetScreenFont(void)
  1091.     {
  1092.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1093.         return geneva;
  1094.     }
  1095.  
  1096.  
  1097. /* Get the ID of the normal monospaced font, usually courier or monaco */
  1098. FontType                        GetMonospacedFont(void)
  1099.     {
  1100.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1101.         return monaco;
  1102.     }
  1103.  
  1104.  
  1105. /* Get the ID of the named font.  If no such font exists, then it is an error */
  1106. FontType                        GetFontByName(char* Name)
  1107.     {
  1108.         unsigned char            NameTemp[256];
  1109.         long                            Scan;
  1110.         short                            FontID;
  1111.  
  1112.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1113.         Scan = 0;
  1114.         while ((Scan < 255) && (Name[Scan] != 0))
  1115.             {
  1116.                 NameTemp[Scan + 1] = Name[Scan];
  1117.                 Scan += 1;
  1118.             }
  1119.         NameTemp[0] = Scan;
  1120.         GetFNum(NameTemp,&FontID);
  1121. #if DEBUG
  1122.         if (FontID == 0)
  1123.             {
  1124.                 unsigned char            SysFontName[256];
  1125.  
  1126.                 GetFontName(0,SysFontName);
  1127.                 for (Scan = 0; Scan <= NameTemp[0]; Scan += 1)
  1128.                     {
  1129.                         if (NameTemp[Scan] != SysFontName[Scan])
  1130.                             {
  1131.                                 PRERR(AllowResume,"GetFontByName:  font doesn't exist");
  1132.                             }
  1133.                     }
  1134.             }
  1135. #endif
  1136.         return FontID;
  1137.     }
  1138.  
  1139.  
  1140. /* Get the total number of pixels high a line is using the specified font */
  1141. OrdType                            GetFontHeight(FontType FontID, FontSizeType PointSize)
  1142.     {
  1143.         GrafPort                    Temp;
  1144.         FontInfo                    TheFont;
  1145.  
  1146.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1147.         OpenPort(&Temp);
  1148.         TextFont(FontID);
  1149.         TextFace(0);
  1150.         TextMode(srcCopy);
  1151.         TextSize(PointSize);
  1152.         SpaceExtra(0);
  1153.         GetFontInfo(&TheFont);
  1154.         ClosePort(&Temp);
  1155.         return TheFont.ascent + TheFont.descent + TheFont.leading;
  1156.     }
  1157.  
  1158.  
  1159. /* return a Ptr containing the name of the font, null terminated */
  1160. char*                                GetNameOfFont(FontType FontID)
  1161.     {
  1162.         unsigned char            DaFontName[256];
  1163.         char*                            Temp;
  1164.  
  1165.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1166.         GetFontName(FontID,DaFontName);
  1167.         ERROR(DaFontName[0] == 0,PRERR(AllowResume,"GetNameOfFont:  nonexistent font"));
  1168.         Temp = AllocPtrCanFail(DaFontName[0] + 1,"FontName");
  1169.         if (Temp != NIL)
  1170.             {
  1171.                 CopyData((char*)&(DaFontName[1]),&(Temp[0]),DaFontName[0]);
  1172.                 Temp[DaFontName[0]] = 0;
  1173.             }
  1174.         return Temp;
  1175.     }
  1176.  
  1177.  
  1178. /* get number of fonts */
  1179. long                                GetNumAvailableFonts(void)
  1180.     {
  1181.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1182.         return CountMItems(FunnyFontMenu);
  1183.     }
  1184.  
  1185.  
  1186. /* get the FontType of an indexed font. indices are from 0 to GetNumAvailableFonts - 1 */
  1187. FontType                        GetIndexedFont(long FontIndex)
  1188.     {
  1189.         short                            DaID;
  1190.         unsigned char            DaName[256];
  1191.  
  1192.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1193.         ERROR((FontIndex < 0) || (FontIndex >= GetNumAvailableFonts()),PRERR(ForceAbort,
  1194.             "GetIndexedFont:  index out of range"));
  1195.         /* we cleverly make a menu, pile the fonts in there, and then extract */
  1196.         GetItem(FunnyFontMenu,FontIndex + 1,DaName);
  1197.         GetFNum(DaName,&DaID);
  1198.         return DaID;
  1199.     }
  1200.  
  1201.  
  1202. /* find the total number of pixels long the string of text is */
  1203. OrdType                            LengthOfText(FontType Font, FontSizeType PointSize, char* Text,
  1204.                                             long Length, FontStyleType FontStyle)
  1205.     {
  1206.         GrafPort                    Temp;
  1207.         long                            CurrentLinePixels;
  1208.         Style                            FontThangs;
  1209.  
  1210.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1211.         /* open a temporary port to work from */
  1212.         OpenPort(&Temp);
  1213.         /* set font */
  1214.         TextFont(Font);
  1215.         /* figure out what style to use */
  1216.         FontThangs = 0;
  1217.         if ((FontStyle & eBold) != 0)
  1218.             {
  1219.                 FontThangs |= bold;
  1220.             }
  1221.         if ((FontStyle & eItalic) != 0)
  1222.             {
  1223.                 FontThangs |= italic;
  1224.             }
  1225.         if ((FontStyle & eUnderline) != 0)
  1226.             {
  1227.                 FontThangs |= underline;
  1228.             }
  1229.         TextFace(FontThangs);
  1230.         TextMode(srcCopy);
  1231.         TextSize(PointSize);
  1232.         SpaceExtra(0);
  1233.         /* loop through string & add up lengths */
  1234.         CurrentLinePixels = 0;
  1235.         while (Length > 0)
  1236.             {
  1237.                 if (Length > MAXTEXTSIZING)
  1238.                     {
  1239.                         CurrentLinePixels += TextWidth(Text,0,MAXTEXTSIZING);
  1240.                         Length -= MAXTEXTSIZING;
  1241.                         Text += MAXTEXTSIZING;
  1242.                     }
  1243.                  else
  1244.                     {
  1245.                         CurrentLinePixels += TextWidth(Text,0,Length);
  1246.                         Length = 0;
  1247.                     }
  1248.             }
  1249.         ClosePort(&Temp);
  1250.         return CurrentLinePixels;
  1251.     }
  1252.  
  1253.  
  1254. /* draw a line of text */
  1255. void                                DrawTextLine(WinType* Window, FontType Font, FontSizeType PointSize,
  1256.                                             char* Text, long Length, OrdType X, OrdType Y,
  1257.                                             FontStyleType FontStyle)
  1258.     {
  1259.         FontInfo                    Info;
  1260.         Style                            FontThangs;
  1261.  
  1262.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1263.         ERROR(Text == NIL,PRERR(ForceAbort,"DrawTextLine:  Text is NIL"));
  1264.         CheckPtrExistence(Window);
  1265.         SetPort((WindowPtr)&(Window->ActualWindow));
  1266.         TextFont(Font);
  1267.         FontThangs = 0;
  1268.         if ((FontStyle & eBold) != 0)
  1269.             {
  1270.                 FontThangs |= bold;
  1271.             }
  1272.         if ((FontStyle & eItalic) != 0)
  1273.             {
  1274.                 FontThangs |= italic;
  1275.             }
  1276.         if ((FontStyle & eUnderline) != 0)
  1277.             {
  1278.                 FontThangs |= underline;
  1279.             }
  1280.         TextFace(FontThangs);
  1281.         TextMode(srcCopy);
  1282.         TextSize(PointSize);
  1283.         SpaceExtra(0);
  1284.         GetFontInfo(&Info);
  1285.         MoveTo(X,Y + Info.leading + Info.ascent);
  1286.         while (Length > 0)
  1287.             {
  1288.                 if (Length > MAXTEXTSIZING)
  1289.                     {
  1290.                         DrawText(Text,0,MAXTEXTSIZING);
  1291.                         Length -= MAXTEXTSIZING;
  1292.                         Text += MAXTEXTSIZING;
  1293.                     }
  1294.                  else
  1295.                     {
  1296.                         DrawText(Text,0,Length);
  1297.                         Length = 0;
  1298.                     }
  1299.             }
  1300.         if (Info.leading > 0)
  1301.             {
  1302.                 Rect                EraseMe;
  1303.  
  1304.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1305.                 EraseMe.left = X;
  1306.                 EraseMe.top = Y;
  1307.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1308.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1309.                 EraseRect(&EraseMe);
  1310.             }
  1311.     }
  1312.  
  1313.  
  1314. /* draw a line of text, but with white background and black letters */
  1315. void                                InvertedTextLine(WinType* Window, FontType Font,
  1316.                                             FontSizeType PointSize, char* Text, long Length,
  1317.                                             OrdType X, OrdType Y, FontStyleType FontStyle)
  1318.     {
  1319.         FontInfo                    Info;
  1320.         Style                            FontThangs;
  1321.  
  1322.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1323.         CheckPtrExistence(Window);
  1324.         SetPort((WindowPtr)&(Window->ActualWindow));
  1325.         TextFont(Font);
  1326.         FontThangs = 0;
  1327.         if ((FontStyle & eBold) != 0)
  1328.             {
  1329.                 FontThangs |= bold;
  1330.             }
  1331.         if ((FontStyle & eItalic) != 0)
  1332.             {
  1333.                 FontThangs |= italic;
  1334.             }
  1335.         if ((FontStyle & eUnderline) != 0)
  1336.             {
  1337.                 FontThangs |= underline;
  1338.             }
  1339.         TextFace(FontThangs);
  1340.         TextMode(notSrcCopy);
  1341.         TextSize(PointSize);
  1342.         SpaceExtra(0);
  1343.         GetFontInfo(&Info);
  1344.         MoveTo(X,Y + Info.leading + Info.ascent);
  1345.         while (Length > 0)
  1346.             {
  1347.                 if (Length > MAXTEXTSIZING)
  1348.                     {
  1349.                         DrawText(Text,0,MAXTEXTSIZING);
  1350.                         Length -= MAXTEXTSIZING;
  1351.                         Text += MAXTEXTSIZING;
  1352.                     }
  1353.                  else
  1354.                     {
  1355.                         DrawText(Text,0,Length);
  1356.                         Length = 0;
  1357.                     }
  1358.             }
  1359.         if (Info.leading > 0)
  1360.             {
  1361.                 Rect                EraseMe;
  1362.  
  1363.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1364.                 EraseMe.left = X;
  1365.                 EraseMe.top = Y;
  1366.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1367.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1368.                 PenPat(&(PatternMapping[eBlack - eWhite]));
  1369.                 PenMode(patCopy);
  1370.                 PaintRect(&EraseMe);
  1371.             }
  1372.     }
  1373.  
  1374.  
  1375. /* move the specified rectangle of of pixels. XDisplacement and YDisplacement */
  1376. /* positive mean to the right and down.  Area opened up is erased with white. */
  1377. /* no area outside of the rectangle is touched. */
  1378. void                                ScrollArea(WinType* Window, OrdType Left, OrdType Top, OrdType Width,
  1379.                                             OrdType Height, OrdType XDisplacement, OrdType YDisplacement)
  1380.     {
  1381.         Rect                            Where;
  1382.         RgnHandle                    UpdateRegion;
  1383.         RgnHandle                    ScreenRegion;
  1384.  
  1385.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1386.         CheckPtrExistence(Window);
  1387.         SetPort((WindowPtr)&(Window->ActualWindow));
  1388.         Where.left = Left;
  1389.         Where.top = Top;
  1390.         Where.right = Left + Width;
  1391.         Where.bottom = Top + Height;
  1392.         UpdateRegion = NewRgn();
  1393.         if (UpdateRegion != NIL)
  1394.             {
  1395.                 ScrollRect(&Where,XDisplacement,YDisplacement,UpdateRegion);
  1396.                 /* we discard the update region because the scroller is expected to redraw */
  1397.                 /* it himself without getting and update event */
  1398.                 DisposeRgn(UpdateRegion);
  1399.             }
  1400.     }
  1401.  
  1402.  
  1403. /* convert a raw packed-byte list of data (upper bit of each byte is leftmost */
  1404. /* on the screen) to an internal bitmap */
  1405. Bitmap*                            MakeBitmap(unsigned char* RawData, OrdType Width, OrdType Height,
  1406.                                             long BytesPerRow)
  1407.     {
  1408.         short                            TrueBytesPerRow;
  1409.         short                            RowScan;
  1410.         short                            ColumnScan;
  1411.         long                            MapIndex;
  1412.         Bitmap*                        Data;
  1413.  
  1414.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1415.         ERROR(RawData == NIL,PRERR(ForceAbort,"MakeBitmap:  data is NIL"));
  1416.         /* calculate local bytes per row so that it's a long-word multiple */
  1417.         TrueBytesPerRow = ((Width + (8 * sizeof(long)) - 1) / (8 * sizeof(long))) * 4;
  1418.         Data = (Bitmap*)AllocPtrCanFail(TrueBytesPerRow * Height + sizeof(Bitmap),"Bitmap");
  1419.         if (Data == NIL)
  1420.             {
  1421.                 return NIL;
  1422.             }
  1423.         MapIndex = 0;
  1424.         for (RowScan = 0; RowScan < Height; RowScan += 1)
  1425.             {
  1426.                 /* copy over one row worth of data */
  1427.                 for (ColumnScan = 0; ColumnScan < BytesPerRow; ColumnScan += 1)
  1428.                     {
  1429.                         Data->Data[MapIndex + ColumnScan] = RawData[ColumnScan];
  1430.                     }
  1431.                 /* pad the extra space with zeros */
  1432.                 for (ColumnScan = 0; ColumnScan < TrueBytesPerRow - BytesPerRow;
  1433.                     ColumnScan += 1)
  1434.                     {
  1435.                         Data->Data[MapIndex + ColumnScan + BytesPerRow] = 0;
  1436.                     }
  1437.                 MapIndex += TrueBytesPerRow;
  1438.                 RawData += BytesPerRow;
  1439.             }
  1440.         /* assign internal values */
  1441.         Data->Width = Width;
  1442.         Data->Height = Height;
  1443.         Data->BytesPerRow = TrueBytesPerRow;
  1444.         /* initialize the system's bitmap */
  1445.         Data->SystemBitmap.baseAddr = (char*)(Data->Data);
  1446.         Data->SystemBitmap.rowBytes = TrueBytesPerRow;
  1447.         Data->SystemBitmap.bounds.left = 0;
  1448.         Data->SystemBitmap.bounds.top = 0;
  1449.         Data->SystemBitmap.bounds.right = Data->Width;
  1450.         Data->SystemBitmap.bounds.bottom = Data->Height;
  1451.         return Data;
  1452.     }
  1453.  
  1454.  
  1455. /* dispose of the bitmap made by MakeBitmap */
  1456. void                                DisposeBitmap(Bitmap* TheBitmap)
  1457.     {
  1458.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1459.         ReleasePtr((char*)TheBitmap);
  1460.     }
  1461.  
  1462.  
  1463. /* copy the bitmap to the area specified. */
  1464. void                                DrawBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1465.     {
  1466.         Rect                            DestRect;
  1467.  
  1468.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1469.         CheckPtrExistence(Window);
  1470.         CheckPtrExistence(TheBitmap);
  1471.         SetPort((WindowPtr)&(Window->ActualWindow));
  1472.         DestRect.left = X;
  1473.         DestRect.top = Y;
  1474.         DestRect.right = X + TheBitmap->Width;
  1475.         DestRect.bottom = Y + TheBitmap->Height;
  1476.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1477.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcCopy,NIL);
  1478.     }
  1479.  
  1480.  
  1481. /* logical-or the bitmap onto the window */
  1482. void                                OrBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1483.     {
  1484.         Rect                            DestRect;
  1485.  
  1486.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1487.         CheckPtrExistence(Window);
  1488.         CheckPtrExistence(TheBitmap);
  1489.         SetPort((WindowPtr)&(Window->ActualWindow));
  1490.         DestRect.left = X;
  1491.         DestRect.top = Y;
  1492.         DestRect.right = X + TheBitmap->Width;
  1493.         DestRect.bottom = Y + TheBitmap->Height;
  1494.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1495.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcOr,NIL);
  1496.     }
  1497.  
  1498.  
  1499. /* Bit-clear the bitmap onto the window:  Where the bitmap is set, the */
  1500. /* window will be erased; otherwise the window will be untouched */
  1501. void                                BicBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1502.     {
  1503.         Rect                            DestRect;
  1504.  
  1505.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1506.         CheckPtrExistence(Window);
  1507.         CheckPtrExistence(TheBitmap);
  1508.         SetPort((WindowPtr)&(Window->ActualWindow));
  1509.         DestRect.left = X;
  1510.         DestRect.top = Y;
  1511.         DestRect.right = X + TheBitmap->Width;
  1512.         DestRect.bottom = Y + TheBitmap->Height;
  1513.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1514.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcBic,NIL);
  1515.     }
  1516.  
  1517.  
  1518. /* duplicate the bitmap */
  1519. Bitmap*                            DuplicateBitmap(Bitmap* Original)
  1520.     {
  1521.         Bitmap*                        Copy;
  1522.         long                            TotalSize;
  1523.  
  1524.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1525.         CheckPtrExistence(Original);
  1526.         /* this is easy since there are no sub-objects */
  1527.         TotalSize = PtrSize((char*)Original);
  1528.         Copy = (Bitmap*)AllocPtrCanFail(TotalSize,"DuplicateBitmap");
  1529.         if (Copy != NIL)
  1530.             {
  1531.                 CopyData((char*)Original,(char*)Copy,TotalSize);
  1532.                 Copy->SystemBitmap.baseAddr = (char*)(Copy->Data);
  1533.             }
  1534.         return Copy;
  1535.     }
  1536.  
  1537.  
  1538. /* logical-or the first bitmap onto the second.  sizes must be the same */
  1539. void                                BitmapOrIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1540.     {
  1541.         long                            Scan;
  1542.         long                            Limit;
  1543.  
  1544.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1545.         CheckPtrExistence(NotChanged);
  1546.         CheckPtrExistence(IsChanged);
  1547.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1548.             || (NotChanged->Width != IsChanged->Width)
  1549.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1550.             "BitmapOrIntoBitmap:  bitmaps are not the same size"));
  1551.         /* we can perform operations on long words since we ensure that our */
  1552.         /* internal bitmap representation is long-word aligned */
  1553.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1554.         for (Scan = 0; Scan < Limit; Scan += 1)
  1555.             {
  1556.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1557.                     sizeof(unsigned long));
  1558.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1559.                     sizeof(unsigned long));
  1560.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1561.                     |= ((unsigned long*)(NotChanged->Data))[Scan];
  1562.             }
  1563.     }
  1564.  
  1565.  
  1566. /* logical-and the first bitmap onto the second.  sizes must be the same */
  1567. void                                BitmapAndIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1568.     {
  1569.         long                            Scan;
  1570.         long                            Limit;
  1571.  
  1572.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1573.         CheckPtrExistence(NotChanged);
  1574.         CheckPtrExistence(IsChanged);
  1575.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1576.             || (NotChanged->Width != IsChanged->Width)
  1577.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1578.             "BitmapAndIntoBitmap:  bitmaps are not the same size"));
  1579.         /* we can perform operations on long words since we ensure that our */
  1580.         /* internal bitmap representation is long-word aligned */
  1581.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1582.         for (Scan = 0; Scan < Limit; Scan += 1)
  1583.             {
  1584.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1585.                     sizeof(unsigned long));
  1586.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1587.                     sizeof(unsigned long));
  1588.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1589.                     &= ((unsigned long*)(NotChanged->Data))[Scan];
  1590.             }
  1591.     }
  1592.